﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Xml;
using WPF = System.Windows.Controls;
using System.Windows.Media;

namespace SHomeWorkshop.LunarPresentation.Expressions
{
    public class GridPanel : SubPanel
    {
        public GridPanel(SubPanel rootPanel, SubPanel parentPanel,
            Editor editor, Expression parentExpression)
            : base(rootPanel, parentPanel, editor, parentExpression)
        {
            HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
            VerticalAlignment = System.Windows.VerticalAlignment.Stretch;

            this.chineseName = "网格子面板";
            this.Margin = cMargin;

            this.borderColor = null;
        }

        public enum GridPanelAlignment
        {
            TopLeft, TopCenter, TopRight,
            Left, Center, Right,
            BottomLeft, BottomCenter, BottomRight
        }

        private GridPanelAlignment panelAlign = GridPanelAlignment.TopLeft;

        public GridPanelAlignment PanelAlign
        {
            get { return panelAlign; }
            set
            {
                panelAlign = value;
                this.XmlData.SetAttribute("PanelAlign", value.ToString());
                RefreshGridPanelAlign();
            }
        }

        private void RefreshGridPanelAlign()
        {
            switch (panelAlign)
            {
                case GridPanelAlignment.TopLeft:
                    {
                        this.basePanel.HorizontalAlignment = HorizontalAlignment.Stretch;
                        this.basePanel.VerticalAlignment = VerticalAlignment.Stretch;
                        break;
                    }
                case GridPanelAlignment.TopCenter:
                    {
                        this.basePanel.HorizontalAlignment = HorizontalAlignment.Center;
                        this.basePanel.VerticalAlignment = VerticalAlignment.Stretch;
                        break;
                    }
                case GridPanelAlignment.TopRight:
                    {
                        this.basePanel.HorizontalAlignment = HorizontalAlignment.Right;
                        this.basePanel.VerticalAlignment = VerticalAlignment.Stretch;
                        break;
                    }
                case GridPanelAlignment.Left:
                    {
                        this.basePanel.HorizontalAlignment = HorizontalAlignment.Stretch;
                        this.basePanel.VerticalAlignment = VerticalAlignment.Center;
                        break;
                    }
                case GridPanelAlignment.Center:
                    {
                        this.basePanel.HorizontalAlignment = HorizontalAlignment.Center;
                        this.basePanel.VerticalAlignment = VerticalAlignment.Center;
                        break;
                    }
                case GridPanelAlignment.Right:
                    {
                        this.basePanel.HorizontalAlignment = HorizontalAlignment.Right;
                        this.basePanel.VerticalAlignment = VerticalAlignment.Center;
                        break;
                    }
                case GridPanelAlignment.BottomLeft:
                    {
                        this.basePanel.HorizontalAlignment = HorizontalAlignment.Stretch;
                        this.basePanel.VerticalAlignment = VerticalAlignment.Bottom;
                        break;
                    }
                case GridPanelAlignment.BottomCenter:
                    {
                        this.basePanel.HorizontalAlignment = HorizontalAlignment.Center;
                        this.basePanel.VerticalAlignment = VerticalAlignment.Bottom;
                        break;
                    }
                case GridPanelAlignment.BottomRight:
                    {
                        this.basePanel.HorizontalAlignment = HorizontalAlignment.Right;
                        this.basePanel.VerticalAlignment = VerticalAlignment.Bottom;
                        break;
                    }
            }
        }

        private static Thickness cMargin = new Thickness(1);

        private int gridX = 0;

        public int GridX
        {
            get { return gridX; }
            set
            {
                if (value >= 0)
                {
                    gridX = value;
                    this.XmlData.SetAttribute("GridX", gridX.ToString());
                    WPF.Grid.SetColumn(this, value);
                }
            }
        }

        private int gridY = 0;

        public int GridY
        {
            get { return gridY; }
            set
            {
                if (value >= 0)
                {
                    gridY = value;
                    this.XmlData.SetAttribute("GridY", gridY.ToString());
                    WPF.Grid.SetRow(this, value);
                }
            }
        }

        private int gridXSpan = 1;

        public int GridXSpan
        {
            get { return gridXSpan; }
            set
            {
                if (value >= 1)
                {
                    gridXSpan = value;
                    this.XmlData.SetAttribute("GridXSpan", gridXSpan.ToString());
                    WPF.Grid.SetColumnSpan(this, value);
                }
            }
        }

        private int gridYSpan = 1;

        public int GridYSpan
        {
            get { return gridYSpan; }
            set
            {
                if (value >= 1)
                {
                    gridYSpan = value;
                    this.XmlData.SetAttribute("GridYSpan", gridYSpan.ToString());
                    WPF.Grid.SetRowSpan(this, value);
                }
            }
        }

        public override SubPanel LeftSubPanel
        {
            get
            {
                if (GridX >= 1)
                {
                    GridPanel gp = (ParentExpression as Grid).GetGridPanel(GridX - 1, GridY);
                    if (gp == null) return null;

                    switch (gp.MergeStanding)
                    {
                        case Standing.Normal:
                        case Standing.Master:
                            {
                                return gp;
                            }
                        case Standing.Slave:
                            {
                                return gp.MasterGridPanel;
                            }
                    }
                }

                return null;
            }
        }

        public override SubPanel RightSubPanel
        {
            get
            {
                if (GridX >= 0)
                {
                    GridPanel gp = (ParentExpression as Grid).GetGridPanel(GridX + GridXSpan, GridY);
                    if (gp == null) return null;

                    switch (gp.MergeStanding)
                    {
                        case Standing.Normal:
                        case Standing.Master:
                            {
                                return gp;
                            }
                        case Standing.Slave:
                            {
                                return gp.MasterGridPanel;
                            }
                    }
                }

                return null;
            }
        }

        public override SubPanel TopSubPanel
        {
            get
            {
                if (GridY >= 1)
                {
                    GridPanel gp = (ParentExpression as Grid).GetGridPanel(GridX, GridY - 1);
                    if (gp == null) return null;

                    switch (gp.MergeStanding)
                    {
                        case Standing.Normal:
                        case Standing.Master:
                            {
                                return gp;
                            }
                        case Standing.Slave:
                            {
                                return gp.MasterGridPanel;
                            }
                    }
                }

                return null;
            }
        }

        public override SubPanel BottomSubPanel
        {
            get
            {
                if (GridY >= 0)
                {
                    GridPanel gp = (ParentExpression as Grid).GetGridPanel(GridX, GridY + GridYSpan);
                    if (gp == null) return null;

                    switch (gp.MergeStanding)
                    {
                        case Standing.Normal:
                        case Standing.Master:
                            {
                                return gp;
                            }
                        case Standing.Slave:
                            {
                                return gp.MasterGridPanel;
                            }
                    }
                }

                return null;
            }
        }

        /// <summary>
        /// 用以处理合并单元格。被合并者为Slave，反之为Master。
        /// 既未被合并，又未合并其它单元格的普通单元格为Normal。
        /// </summary>
        public enum Standing { Master, Slave, Normal }

        private Standing mergeStanding = Standing.Normal;

        public Standing MergeStanding
        {
            get { return mergeStanding; }
            set
            {
                mergeStanding = value;
                if (this.XmlData != null)
                {
                    this.XmlData.SetAttribute
                        ("MergeStanding", mergeStanding.ToString());
                }

                UpdateMergeVisibility();
            }
        }

        protected void UpdateMergeVisibility()
        {
            switch (mergeStanding)
            {
                case Standing.Master:
                    {
                        this.Visibility = System.Windows.Visibility.Visible;

                        XmlAttribute aGridXSpan = this.XmlData.GetAttribute("GridXSpan");
                        if (aGridXSpan != null)
                        {
                            this.gridXSpan = int.Parse(aGridXSpan.Value);
                        }
                        WPF.Grid.SetColumnSpan(this, this.gridXSpan);

                        XmlAttribute aGridYSpan = this.XmlData.GetAttribute("GridYSpan");
                        if (aGridYSpan != null)
                        {
                            this.gridYSpan = int.Parse(aGridYSpan.Value);
                        }
                        WPF.Grid.SetRowSpan(this, this.gridYSpan);

                        break;
                    }
                case Standing.Normal:
                    {
                        this.Visibility = System.Windows.Visibility.Visible; break;
                    }
                case Standing.Slave:
                    {
                        this.Visibility = System.Windows.Visibility.Hidden; break;
                    }
            }
        }

        protected override void BuildChildren()
        {
            base.BuildChildren();

            if (this.XmlData == null) return;

            try
            {
                XmlAttribute attrPanelAlign = this.XmlData.GetAttribute("PanelAlign");
                if (attrPanelAlign != null)
                {
                    this.panelAlign = (GridPanelAlignment)Enum.Parse(typeof(GridPanelAlignment), attrPanelAlign.Value);
                    RefreshGridPanelAlign();
                }

                XmlAttribute aMergeStanding = this.XmlData.GetAttribute("MergeStanding");
                if (aMergeStanding != null)
                {
                    this.mergeStanding = (Standing)Enum.Parse(typeof(Standing), aMergeStanding.Value);

                    // 只有合并或被合并单元格才有必要进行此步处理。
                    UpdateMergeVisibility();
                }

                XmlAttribute attrGridX = this.XmlData.GetAttribute("GridX");
                if (attrGridX != null)
                {
                    this.gridX = int.Parse(attrGridX.Value);
                }

                XmlAttribute attrGridY = this.XmlData.GetAttribute("GridY");
                if (attrGridY != null)
                {
                    this.gridY = int.Parse(attrGridY.Value);
                }

                XmlAttribute attrGridXSpan = this.XmlData.GetAttribute("GridXSpan");
                if (attrGridXSpan != null)
                {
                    this.gridXSpan = int.Parse(attrGridXSpan.Value);
                }

                XmlAttribute attrGridYSpan = this.XmlData.GetAttribute("GridYSpan");
                if (attrGridYSpan != null)
                {
                    this.gridYSpan = int.Parse(attrGridYSpan.Value);
                }

                XmlAttribute attrMasterX = this.XmlData.GetAttribute("MasterX");
                if (attrMasterX != null)
                {
                    this.masterX = int.Parse(attrMasterX.Value);
                }

                XmlAttribute attrMasterY = this.XmlData.GetAttribute("MasterY");
                if (attrMasterY != null)
                {
                    this.masterY = int.Parse(attrMasterY.Value);
                }

                RefreshDefBorderColor();
            }
            catch (Exception ex)
            {
                Dialogs.LunarMsgBox.MsgBoxShow(
                    Globals.appName,
                    "发生意外错误，网格子面板未能顺利生成！",
                    "异常信息如下：\r\n" + ex.Message,
                    ex.StackTrace, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
        }

        private void RefreshDefBorderColor()
        {
            XmlAttribute attrBorderColor = this.XmlData.GetAttribute("BorderColor");
            if (attrBorderColor == null)
            {
                //Binding borderBinding = new Binding();
                //borderBinding.Source = this.Editor.DefaultForeground;
                //this.mainBorder.SetBinding(Border.BorderBrushProperty, borderBinding);

                //考虑到“行”不需要自动以前景色的方式出现。
                //且未找到“取消绑定”的办法。此处未使用“绑定”来实现。
                //更改编辑器“默认前景色”后，将使用递归来实现“自动边框前景色”的更新。
                if (this.editor != null)
                {
                    this.mainBorder.BorderBrush = this.Editor.DefaultForeground;
                }
            }
            else
            {
                Brush resultBsh = ColorPicker.GetBrushByName(attrBorderColor.Value);
                if (resultBsh == null)
                {
                    this.borderColor = null;
                    this.mainBorder.BorderBrush = editor.DefaultForeground;
                }
                else
                {
                    this.mainBorder.BorderBrush = resultBsh;
                }
            }
        }

        protected int masterX = -1;

        /// <summary>
        /// 覆盖者的横坐标索引。当MergeStanding为Normal时，此坐标应为-1。
        /// </summary>
        public int MasterX
        {
            get { return masterX; }
            set
            {
                masterX = value;
                if (this.XmlData != null)
                {
                    this.XmlData.SetAttribute("MasterX", masterX.ToString());
                }
            }
        }

        private int masterY = -1;

        /// <summary>
        /// 覆盖者的纵坐标索引。当MergeStanding为Normal时，此坐标应为-1。
        /// </summary>
        public int MasterY
        {
            get { return masterY; }
            set
            {
                masterY = value;
                if (this.XmlData != null)
                {
                    this.XmlData.SetAttribute("MasterY", masterY.ToString());
                }
            }
        }

        public GridPanel MasterGridPanel
        {
            get
            {
                switch (mergeStanding)
                {
                    case Standing.Slave:
                        {
                            if (masterX >= 0 && masterY >= 0)
                            {
                                Grid grid = this.ParentExpression as Grid;
                                return grid.GetGridPanel(masterX, masterY);
                            }

                            return null;
                        }
                    default: return null;
                }
            }
        }

        /// <summary>
        /// 向右合并。
        /// </summary>
        public void MergeRight()
        {
            // 先判断目标区域是否可以合并。
            // 基本规则是：
            // ①存在单元格；
            // ②这些单元格没有被其它单元格合并；
            // ③这些单元格没有合并过其它单元格。

            ModifingItem mi = new ModifingItem();

            List<GridPanel> panels = new List<GridPanel>();

            Grid parentGrid = this.ParentExpression as Grid;

            for (int i = 0; i < GridYSpan; i++)
            {
                GridPanel gp = parentGrid.GetGridPanel(gridX + gridXSpan, gridY + i);
                if (gp == null) return;//已到最右侧。

                switch (gp.mergeStanding)
                {
                    case Standing.Slave:
                    case Standing.Master:
                        {
                            System.Windows.MessageBox.Show(
                            "目标合并区域已存在一个或更多的合并单元格，不能重叠合并！",
                            Globals.appName, System.Windows.MessageBoxButton.OK,
                            System.Windows.MessageBoxImage.Warning);
                            return;
                        }
                    case Standing.Normal:
                        {
                            panels.Add(gp);
                            break;
                        }
                }
            }

            Action actionOfXSpan = new Action(this.ExID, -1,
                this.GetType().Name, "GridXSpan", this.gridXSpan.ToString(), (this.GridXSpan + 1).ToString());
            mi.Add(actionOfXSpan);

            this.GridXSpan += 1;
            foreach (GridPanel gp in panels)
            {
                Action actOfMaxterX = new Action(gp.ExID, -1,
                    gp.GetType().Name, "MasterX", gp.masterX.ToString(), gridX.ToString());
                Action actOfMaxterY = new Action(gp.ExID, -1,
                    gp.GetType().Name, "MasterY", gp.masterY.ToString(), gridY.ToString());
                Action actOfStanding = new Action(gp.ExID, -1,
                    gp.GetType().Name, "MergeStanding", gp.mergeStanding.ToString(), Standing.Slave.ToString());

                gp.MasterX = gridX;
                gp.MasterY = gridY;
                gp.MergeStanding = Standing.Slave;

                mi.Add(actOfMaxterX); mi.Add(actOfMaxterY); mi.Add(actOfStanding);
            }

            this.MergeStanding = Standing.Master;// 注意顺序。

            Action actionOfMerGeStanding = new Action(this.ExID, -1,
                this.GetType().Name, "MergeStanding", this.mergeStanding.ToString(), Standing.Master.ToString());

            mi.Add(actionOfMerGeStanding);

            Editor.Do(mi);
            Editor.IsModified = true;
        }

        /// <summary>
        /// 向下合并。
        /// </summary>
        /// <returns></returns>
        public void MergeBottom()
        {
            // 先判断目标区域是否可以合并。
            // 基本规则是：
            // ①存在单元格；
            // ②这些单元格没有被其它单元格合并；
            // ③这些单元格没有合并过其它单元格。

            ModifingItem mi = new ModifingItem();

            List<GridPanel> panels = new List<GridPanel>();

            Grid parentGrid = this.ParentExpression as Grid;

            for (int i = 0; i < GridXSpan; i++)
            {
                GridPanel gp = parentGrid.GetGridPanel(gridX + i, gridY + gridYSpan);
                if (gp == null) return;//已到最底端。

                switch (gp.mergeStanding)
                {
                    case Standing.Slave:
                    case Standing.Master:
                        {
                            System.Windows.MessageBox.Show(
                            "目标合并区域已存在一个或更多的合并单元格，不能重叠合并！",
                            Globals.appName, System.Windows.MessageBoxButton.OK,
                            System.Windows.MessageBoxImage.Warning);
                            return;
                        }
                    case Standing.Normal:
                        {
                            panels.Add(gp);
                            break;
                        }
                }
            }

            Action actionOfYSpan = new Action(this.ExID, -1,
                this.GetType().Name, "GridYSpan", this.gridYSpan.ToString(), (this.GridYSpan + 1).ToString());
            mi.Add(actionOfYSpan);

            this.GridYSpan += 1;

            foreach (GridPanel gp in panels)
            {
                Action actOfMaxterX = new Action(gp.ExID, -1,
                    gp.GetType().Name, "MasterX", gp.masterX.ToString(), gridX.ToString());
                Action actOfMaxterY = new Action(gp.ExID, -1,
                    gp.GetType().Name, "MasterY", gp.masterY.ToString(), gridY.ToString());
                Action actOfStanding = new Action(gp.ExID, -1,
                    gp.GetType().Name, "MergeStanding", gp.mergeStanding.ToString(), Standing.Slave.ToString());

                gp.MasterX = gridX;
                gp.MasterY = gridY;
                gp.MergeStanding = Standing.Slave;

                mi.Add(actOfMaxterX); mi.Add(actOfMaxterY); mi.Add(actOfStanding);
            }

            Action actionOfMerGeStanding = new Action(this.ExID, -1,
                this.GetType().Name, "MergeStanding", this.mergeStanding.ToString(), Standing.Master.ToString());

            mi.Add(actionOfMerGeStanding);

            this.MergeStanding = Standing.Master;// 注意顺序。

            Editor.Do(mi);
            Editor.IsModified = true;
        }

        /// <summary>
        /// 取消合并。
        /// </summary>
        public void MergeCancel()
        {
            List<GridPanel> panels = new List<GridPanel>();

            Grid parentGrid = this.ParentExpression as Grid;

            ModifingItem mi = new ModifingItem();

            for (int i = gridX; i < gridX + gridXSpan; i++)
            {
                for (int j = gridY; j < gridY + gridYSpan; j++)
                {
                    GridPanel gp = parentGrid.GetGridPanel(i, j);
                    if (gp != null)
                    {
                        Action action = new Action(gp.ExID, -1,
                            gp.GetType().Name, "MergeStanding", gp.mergeStanding.ToString(),
                            Standing.Normal.ToString());
                        mi.Add(action);

                        gp.MergeStanding = Standing.Normal;
                        gp.MasterX = -1;
                        gp.MasterY = -1;
                    }
                }
            }

            //this.MergeStanding = Standing.Normal;// 已执行过了。

            Action actionOfXSpan = new Action(this.ExID, -1,
                this.GetType().Name, "GridXSpan", this.GridXSpan.ToString(), "1");
            mi.Add(actionOfXSpan);

            Action actionOfYSpan = new Action(this.ExID, -1,
                this.GetType().Name, "GridYSpan", this.GridYSpan.ToString(), "1");
            mi.Add(actionOfYSpan);

            this.GridXSpan = 1;
            this.GridYSpan = 1;

            Editor.Do(mi);
            Editor.IsModified = true;
        }

        public override void SetProperty(string propertyName, string value)
        {
            base.SetProperty(propertyName, value);

            switch (propertyName)
            {
                //case "Indent":
                //    {
                //        this.Indent = int.Parse(value);
                //        break;
                //    }
                case "GridX":
                    {
                        this.GridX = int.Parse(value);
                        break;
                    }
                case "GridY":
                    {
                        this.GridY = int.Parse(value);
                        break;
                    }
                case "GridYSpan":
                    {
                        this.GridYSpan = int.Parse(value);
                        break;
                    }
                case "GridXSpan":
                    {
                        this.GridXSpan = int.Parse(value);
                        break;
                    }
                case "MergeStanding":
                    {
                        this.MergeStanding = (Standing)Enum.Parse(typeof(Standing), value, true);
                        break;
                    }
                case "MasterX":
                    {
                        this.MasterX = int.Parse(value);
                        break;
                    }
                case "MasterY":
                    {
                        this.MasterY = int.Parse(value);
                        break;
                    }
                case "PanelAlign":
                    {
                        this.PanelAlign = (GridPanelAlignment)Enum.Parse(typeof(GridPanelAlignment), value);
                        RefreshGridPanelAlign();
                        break;
                    }
                case "BorderColor":
                    {
                        if (value == "UnKnown")
                        {
                            this.XmlData.RemoveAttributeByName("BorderColor");
                        }

                        RefreshDefBorderColor();
                        break;
                    }
            }
        }
    }
}
